package com.fpd.tools;

import com.fpd.model.bean.CellBean;
import io.swagger.annotations.ApiModelProperty;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.util.CellAddress;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.util.CollectionUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ExcelUtil {
    /**
     * 导出Excel
     * @param sheetName sheet名称
     * @param title 标题
     * @param values 内容
     * @param wb HSSFWorkbook对象
     * @return
     */
    public static HSSFWorkbook getHSSFWorkbook(String sheetName, String []title, String [][]values, HSSFWorkbook wb){

        // 第一步，创建一个HSSFWorkbook，对应一个Excel文件
        if(wb == null){
            wb = new HSSFWorkbook();
        }

        // 第二步，在workbook中添加一个sheet,对应Excel文件中的sheet
        HSSFSheet sheet = wb.createSheet(sheetName);


        // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        HSSFRow row = sheet.createRow(0);

        // 第四步，创建单元格，并设置值表头 设置表头居中

        HSSFCellStyle style = wb.createCellStyle();
        //        style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式
//        style.setBorderBottom((short) 1);//下边框
//        style.setBorderLeft((short) 1);//左边框
//        style.setBorderRight((short) 1);//右边框
//        style.setBorderTop((short) 1); //上边框


        //声明列对象
        HSSFCell cell = null;

        //创建标题
        for(int i=0;i<title.length;i++){
            cell = row.createCell(i);
            cell.setCellValue(title[i]);
            cell.setCellStyle(style);
        }

        //声明列对象
        HSSFCell cellContent = null;
        //创建内容
        for(int i=0;i<values.length;i++){

            row = sheet.createRow(i + 1);
            for(int j=0;j<values[i].length;j++){
                //将内容按顺序赋给对应的列对象
//                sheet.autoSizeColumn(j);
                row.createCell(j).setCellValue(values[i][j]);
//                cellContent = row.createCell(j);
//                cellContent.setCellValue(values[i][j]);
//                cellContent.setCellStyle(style);
            }
        }
        return wb;
    }


    public static XSSFWorkbook getXSSFWorkbook(String sheetName, String []title, String [][]values, XSSFWorkbook  wb){

        // 第一步，创建一个HSSFWorkbook，对应一个Excel文件
        if(wb == null){
            wb = new XSSFWorkbook ();
        }

        // 第二步，在workbook中添加一个sheet,对应Excel文件中的sheet
        XSSFSheet sheet = wb.createSheet(sheetName);
        // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        XSSFRow row = sheet.createRow(0);
        // 第四步，创建单元格，并设置值表头 设置表头居中
        XSSFCellStyle style = wb.createCellStyle();
//        style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式
//        style.setBorderBottom((short) 1);//下边框
//        style.setBorderLeft((short) 1);//左边框
//        style.setBorderRight((short) 1);//右边框
//        style.setBorderTop((short) 1); //上边框


        //声明列对象
        XSSFCell cell = null;

        //创建标题
        for(int i=0;i<title.length;i++){
            cell = row.createCell(i);
            cell.setCellValue(title[i]);
            cell.setCellStyle(style);
        }

        //声明列对象
        HSSFCell cellContent = null;
        //创建内容
        for(int i=0;i<values.length;i++){

            row = sheet.createRow(i + 1);
            for(int j=0;j<values[i].length;j++){
                //将内容按顺序赋给对应的列对象
//                sheet.autoSizeColumn(j);
                row.createCell(j).setCellValue(values[i][j]);
//                cellContent = row.createCell(j);
//                cellContent.setCellValue(values[i][j]);
//                cellContent.setCellStyle(style);
            }
        }
        return wb;
    }

    /**
     * 解析数据集合，生成Excel<p>
     * 注：根据反射解析对象集合，需要集合中所有元素的对象类型一致
     * @param sheetName Excel中的sheet名称
     * @param list 需要导出的数据对象集合
     * @return
     */
    public static HSSFWorkbook getHSSFWorkbook(String sheetName, List<? extends Object> list) {
        if (CollectionUtils.isEmpty(list)) {
            throw new NullPointerException("参数list不能为空");
        }
        if (StringUtils.isBlank(sheetName)) {
            sheetName = "sheet1";
        }

        // 需要导出的属性字段集合
        List<Field> fieldList = new ArrayList<>();
        // 表头集合
        List<String> titleList = new ArrayList<>();
        //隐藏属性集合
        List<Boolean> hiddenList = new ArrayList<>();
        // 获取对象属性值
        Field[] fields = list.get(0).getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            // 获取属性的@ApiModelProperty注解对象
            ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
            if (apiModelProperty == null) {
                // 没有配置注解则跳过
                continue;
            }
            // 获取value值为表头名称
            String title = apiModelProperty.value();
            if (StringUtils.isBlank(title)) {
                // value值为空的，则取属性字段名为表头
                title = field.getName();
            }
            titleList.add(title);

            //获取hidden值为隐藏标识
            Boolean hiddenFlag = apiModelProperty.hidden();
            hiddenList.add(hiddenFlag);

            // 选择需要的属性字段
            fieldList.add(field);
        }
        List<List<String>> rowList = getRowList(list, fieldList);


        // 第一步，创建一个HSSFWorkbook，对应一个Excel文件
        HSSFWorkbook wb = new HSSFWorkbook();
        // 第二步，在workbook中添加一个sheet,对应Excel文件中的sheet
        HSSFSheet sheet = wb.createSheet(sheetName);
        // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        HSSFRow row = sheet.createRow(0);
        // 第四步，创建单元格，并设置值表头 设置表头居中
        HSSFCellStyle style = wb.createCellStyle();
        // 创建一个居中格式
//        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
//        // 下边框
//        style.setBorderBottom((short) 1);
//        // 左边框
//        style.setBorderLeft((short) 1);
//        // 右边框
//        style.setBorderRight((short) 1);
//        // 上边框
//        style.setBorderTop((short) 1);

        // 声明列对象
        HSSFCell cell = null;
        // 创建标题
        for (int i = 0; i < titleList.size(); i++) {
            cell = row.createCell(i);
            cell.setCellValue(titleList.get(i));
            cell.setCellStyle(style);
        }
        // 声明列对象
        HSSFCell cellContent = null;
        // 创建内容
        for (int i = 0; i < rowList.size(); i++) {
            row = sheet.createRow(i + 1);
            List<String> rowValueList = rowList.get(i);
            for (int j = 0; j < rowValueList.size(); j++) {
                // 将内容按顺序赋给对应的列对象
                sheet.autoSizeColumn(j);
                if(hiddenList.get(j)){
                    sheet.setColumnWidth(j,0);
                }else{
                    sheet.setColumnWidth(j, sheet.getColumnWidth(j) * 17 / 10);
                }
                cellContent = row.createCell(j);
                cellContent.setCellValue(rowValueList.get(j));
                cellContent.setCellStyle(style);
            }
        }
        return wb;
    }

    /**
     * 解析数据集合，生成Excel<p>
     * 注：根据反射解析对象集合，需要集合中所有元素的对象类型一致
     * @param sheetName Excel中的sheet名称
     * @param list 需要导出的数据对象集合
     * @return
     */
    public static HSSFWorkbook getSimpleHSSFWorkbook(String sheetName, List<? extends Object> list) {
        if (CollectionUtils.isEmpty(list)) {
            throw new NullPointerException("参数list不能为空");
        }
        if (StringUtils.isBlank(sheetName)) {
            sheetName = "sheet1";
        }

        // 需要导出的属性字段集合
        List<Field> fieldList = new ArrayList<>();
        // 表头集合
        List<String> titleList = new ArrayList<>();
        // 获取对象属性值
        Field[] fields = list.get(0).getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            // 获取属性的@ApiModelProperty注解对象
            ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
            if (apiModelProperty == null || apiModelProperty.hidden()) {
                // 没有配置注解、或 隐藏的属性，则跳过
                continue;
            }
            // 获取value值为表头名称
            String title = apiModelProperty.value();
            if (StringUtils.isBlank(title)) {
                // value值为空的，则取属性字段名为表头
                title = field.getName();
            }
            titleList.add(title);

            // 选择需要的属性字段
            fieldList.add(field);
        }
//        List<List<String>> rowList = getRowList(list, fieldList);


        // 第一步，创建一个HSSFWorkbook，对应一个Excel文件
        HSSFWorkbook wb = new HSSFWorkbook();
        // 第二步，在workbook中添加一个sheet,对应Excel文件中的sheet
        HSSFSheet sheet = wb.createSheet(sheetName);
        // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        HSSFRow row = sheet.createRow(0);
        // 第四步，创建单元格，并设置值表头 设置表头居中
        HSSFCellStyle style = wb.createCellStyle();
        // 声明列对象
        HSSFCell cell = null;
        // 创建标题
        for (int i = 0; i < titleList.size(); i++) {
            cell = row.createCell(i);
            cell.setCellValue(titleList.get(i));
            cell.setCellStyle(style);
        }
        // 声明列对象
        HSSFCell cellContent = null;
        // 读取属性值的get方法集合，key为属性名称
        Map<String, Method> methodMap = getGetMethodMap(list.get(0).getClass(), fieldList);
        Method readMethod = null;
        // 创建内容
        for (int i = 0; i < list.size(); i++) {
            row = sheet.createRow(i + 1);
            for (int j = 0; j < fieldList.size(); j++) {
                Field field = fieldList.get(j);
                Object value = null;
                String content = "";
                try {
                    // 通过get方法读取属性值，这样可以支持get方法自定义返回值
                    readMethod = methodMap.get(field.getName());
                    if (readMethod != null) {
                        value = readMethod.invoke(list.get(i));
                    }
                } catch (Exception e) {

                }
                if (value == null) {
                    continue;
                }
                if (value instanceof Date) {
                    // 日期统一使用yyyy-MM-dd HH:mm:ss格式
                    content = DateUtil.parseDateToStr((Date) value, DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
                } else {
                    // 其它类型统一转换成字符串
                    content = String.valueOf(value);
                }
                // 将内容按顺序赋给对应的列对象
//                sheet.autoSizeColumn(j);
                row.createCell(j).setCellValue(content);
//                cellContent.setCellValue(content);
//                cellContent.setCellStyle(style);
            }
        }
        return wb;
    }

    /**
     * 根据反射解析list集合，转换为Excel rowList
     * @param list 需要解析的集合
     * @param fieldList 集合对象类型的属性字段集合
     * @return
     */
    private static List<List<String>> getRowList(List<? extends Object> list, List<Field> fieldList) {
        // 行集合
        List<List<String>> rowList = new ArrayList<>();
        // 读取属性值的get方法集合，key为属性名称
        Map<String, Method> methodMap = getGetMethodMap(list.get(0).getClass(), fieldList);

        // 解析导出内容集合
        for (Object obj : list) {
            List<String> row = new ArrayList<>();
            for (Field field : fieldList) {
                field.setAccessible(true);
                Object value = null;
                try {
                    // 通过get方法读取属性值，这样可以支持get方法自定义返回值
                    Method readMethod = methodMap.get(field.getName());
                    if (readMethod != null) {
                        value = readMethod.invoke(obj);
                    }
                } catch (Exception e) {

                }
                if (value == null) {
                    row.add("");
                    continue;
                }
                if (value instanceof Date) {
                    // 日期统一使用yyyy-MM-dd HH:mm:ss格式
                    row.add(DateUtil.parseDateToStr((Date) value, DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS));
                } else {
                    // 其它类型统一转换成字符串
                    row.add(String.valueOf(value));
                }
            }
            rowList.add(row);
        }
        return rowList;
    }


    /**
     * 解析数据集合，生成Excel<p>
     * 注：支持表头跨行跨列
     * @param sheetName Excel中的sheet名称
     * @param titleList 表头
     * @param dataKeyList 单元格取值key
     * @param dataList 需要导出的数据对象集合
     * @param footRow 追加的尾行(用于统计时使用)
     * @return
     */
    public static HSSFWorkbook getHSSFWorkbookNew(String sheetName, List<List<CellBean>> titleList, List<String> dataKeyList, List<Map<String, Object>> dataList, List<CellBean> footRow) {
        if (CollectionUtils.isEmpty(titleList)) {
            throw new NullPointerException("参数 titleList 不能为空");
        }
        if (CollectionUtils.isEmpty(dataKeyList)) {
            throw new NullPointerException("参数 dataKeyList 不能为空");
        }
        if (CollectionUtils.isEmpty(dataList)) {
            throw new NullPointerException("参数 dataList 不能为空");
        }
        if (StringUtils.isBlank(sheetName)) {
            sheetName = "sheet1";
        }
        // 第一步，创建一个HSSFWorkbook，对应一个Excel文件
        HSSFWorkbook wb = new HSSFWorkbook();
        // 第二步，在workbook中添加一个sheet,对应Excel文件中的sheet
        HSSFSheet sheet = wb.createSheet(sheetName);

        // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        //HSSFRow row = sheet.createRow(0);
        // 第四步，创建单元格，并设置值表头 设置表头居中
        HSSFCellStyle style = wb.createCellStyle();
        // 水平居中
        style.setAlignment(HorizontalAlignment.CENTER);
        // 垂直居中
        style.setVerticalAlignment(VerticalAlignment.CENTER);

        // 设置边框
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);

        // 加粗
        HSSFFont font = wb.createFont();
        font.setBold(true);
        style.setFont(font);

        // 表头占用总行数(跨行表头，后续写入数据时以此定位起始行号)
        int titleColNum = titleList.size();
        // 解析表头
        for (int i = 0; i < titleList.size(); i++) {
            List<CellBean> cellBeanList = titleList.get(i);
            if (CollectionUtils.isEmpty(cellBeanList)) {
                continue;
            }
            HSSFRow row = sheet.createRow(i);
            for (int j = 0; j < cellBeanList.size(); j++) {
                CellBean cellBean = cellBeanList.get(j);
                HSSFCell cell = row.createCell(j);
                cell.setCellStyle(style);
                if (cellBean == null) {
                    continue;
                }
                if (cellBean.getRowspan() > 0 || cellBean.getColspan() > 0) {
                    // 跨行跨列
                    sheet.addMergedRegion(new CellRangeAddress(i, i + cellBean.getRowspan(), j, j + cellBean.getColspan()));
                }
                String value = cellBean.getValue().toString();
                int width = getCellColumnWidth(value);
                sheet.setColumnWidth(j, width);

                cell.setCellValue(value);
            }
        }
        // 最后一行数据的行索引
        int rowIndex = titleColNum - 1;
        // 声明列对象
        HSSFCell cellContent = null;
        // 创建内容
        for (int i = 0; i < dataList.size(); i++) {
            rowIndex++;
            HSSFRow row = sheet.createRow(rowIndex);
            Map<String, Object> dataMap = dataList.get(i);

            for (int j = 0; j < dataKeyList.size(); j++) {
                String key = dataKeyList.get(j);
                if (StringUtils.isBlank(key)) {
                    continue;
                }
                Object value = getValueForMap(key, dataMap);
                if (value == null) {
                    continue;
                }
                // 计算宽度
                String t_value = String.valueOf(value);
                int width = getCellColumnWidth(t_value);
                int currentWidth = sheet.getColumnWidth(j);
                if (currentWidth < width) {
                    sheet.setColumnWidth(j, width);
                }
                cellContent = row.createCell(j);
                // 判断值类型
                if (value instanceof BigDecimal) {
                    cellContent.setCellValue(((BigDecimal) value).doubleValue());
                } else if (value instanceof Long || value instanceof Integer) {
                    cellContent.setCellValue(Double.parseDouble(value.toString()));
                } else {
                    cellContent.setCellValue(String.valueOf(value));
                }
            }
        }
        if (CollectionUtils.isEmpty(footRow)) {
            return wb;
        }
        rowIndex++;
        HSSFRow row = sheet.createRow(rowIndex);
        for (int i = 0; i < footRow.size(); i++) {
            CellBean cellBean = footRow.get(i);

            HSSFCell cell = row.createCell(i);
            if (cellBean == null) {
                continue;
            }
            if (cellBean.getContentType().equals(CellBean.CellContentType.TEXT)) {
                // 普通文本
                String value = cellBean.getValue().toString();
                int width = getCellColumnWidth(value);
                int currentWidth = sheet.getColumnWidth(i);
                if (currentWidth < width) {
                    sheet.setColumnWidth(i, width);
                }
                cell.setCellValue(value);
            } else if (cellBean.getContentType().equals(CellBean.CellContentType.FX)) {
                // 公式

                // 获取列坐标前缀
                CellAddress cellAddress = cell.getAddress();
                String address = cellAddress.formatAsString();
                address = address.replaceAll(String.valueOf(cellAddress.getRow() + 1), "");

                // 计算起始行号、结束行号(行号=行索引+1)
                int startRowNum = titleColNum + 1;
                // 结束行在当前行上一行
                int endRowNum = rowIndex;

                // 拼接公式
                StringBuilder sb = new StringBuilder();
                sb.append(cellBean.getValue().toString()).append("(");
                sb.append(address).append(startRowNum).append(":");
                sb.append(address).append(endRowNum).append(")");

                cell.setCellFormula(sb.toString());
            }
        }
        return wb;
    }



    /**
     * 解析数据集合，生成Excel<p>
     * 注：支持表头跨行跨列
     * @param sheetName Excel中的sheet名称
     * @param titleList 表头
     * @param dataKeyList 单元格取值key
     * @param dataList 需要导出的数据对象集合
     * @param footRow 追加的尾行(用于统计时使用)
     * @return
     */
    public static HSSFWorkbook getMyHSSFWorkbook(String sheetName, List<List<CellBean>> titleList, List<String> dataKeyList, List<Map<String, Object>> dataList, List<CellBean> footRow) {
        if (CollectionUtils.isEmpty(titleList)) {
            throw new NullPointerException("参数 titleList 不能为空");
        }
        if (CollectionUtils.isEmpty(dataKeyList)) {
            throw new NullPointerException("参数 dataKeyList 不能为空");
        }
        if (CollectionUtils.isEmpty(dataList)) {
            throw new NullPointerException("参数 dataList 不能为空");
        }
        if (StringUtils.isBlank(sheetName)) {
            sheetName = "sheet1";
        }
        // 第一步，创建一个HSSFWorkbook，对应一个Excel文件
        HSSFWorkbook wb = new HSSFWorkbook();
        // 第二步，在workbook中添加一个sheet,对应Excel文件中的sheet
        HSSFSheet sheet = wb.createSheet(sheetName);

        // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        //HSSFRow row = sheet.createRow(0);
        // 第四步，创建单元格，并设置值表头 设置表头居中
        HSSFCellStyle style = wb.createCellStyle();
        // 水平居中
        style.setAlignment(HorizontalAlignment.CENTER);
        // 垂直居中
        style.setVerticalAlignment(VerticalAlignment.CENTER);

        // 设置边框
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);

        // 加粗
        HSSFFont font = wb.createFont();
        font.setBold(true);
        style.setFont(font);

        // 表头占用总行数(跨行表头，后续写入数据时以此定位起始行号)
        int titleColNum = titleList.size();
        // 解析表头
        for (int i = 0; i < titleList.size(); i++) {
            List<CellBean> cellBeanList = titleList.get(i);
            if (CollectionUtils.isEmpty(cellBeanList)) {
                continue;
            }
            HSSFRow row = sheet.createRow(i);
            for (int j = 0; j < cellBeanList.size(); j++) {
                CellBean cellBean = cellBeanList.get(j);
                HSSFCell cell = row.createCell(j);
                cell.setCellStyle(style);
                if (cellBean == null) {
                    continue;
                }
                if (cellBean.getRowspan() > 0 || cellBean.getColspan() > 0) {
                    // 跨行跨列
                    sheet.addMergedRegion(new CellRangeAddress(i, i + cellBean.getRowspan(), j, j + cellBean.getColspan()));
                }
                String value = cellBean.getValue().toString();
                int width = getCellColumnWidth(value);
                sheet.setColumnWidth(j, width);

                cell.setCellValue(value);
            }
        }
        // 最后一行数据的行索引
        int rowIndex = titleColNum - 1;
        // 声明列对象
        HSSFCell cellContent = null;
        HSSFCellStyle cs = wb.createCellStyle();
        HSSFFont cf = wb.createFont();
        cf.setColor(HSSFFont.COLOR_RED);
        cs.setFont(cf);
        // 创建内容
        for (int i = 0; i < dataList.size(); i++) {
            rowIndex++;
            HSSFRow row = sheet.createRow(rowIndex);
            Map<String, Object> dataMap = dataList.get(i);

            for (int j = 0; j < dataKeyList.size(); j++) {
                String key = dataKeyList.get(j);
                if (StringUtils.isBlank(key)) {
                    continue;
                }
                Object value = getValueForMap(key, dataMap);
                if (value == null) {
                    continue;
                }
                // 计算宽度
                String t_value = String.valueOf(value);
                int width = getCellColumnWidth(t_value);
                int currentWidth = sheet.getColumnWidth(j);
                if (currentWidth < width) {
                    sheet.setColumnWidth(j, width);
                }
                cellContent = row.createCell(j);
                // 判断值类型
                if(t_value.contains("(格式错误)-red") || t_value.contains("(不能为空)-red")){
                    cellContent.setCellStyle(cs);
                    cellContent.setCellValue(t_value.split("-")[0]);
                }else{
                    cellContent.setCellValue(t_value);
                }
            }
        }
        if (CollectionUtils.isEmpty(footRow)) {
            return wb;
        }
        rowIndex++;
        HSSFRow row = sheet.createRow(rowIndex);
        for (int i = 0; i < footRow.size(); i++) {
            CellBean cellBean = footRow.get(i);

            HSSFCell cell = row.createCell(i);
            if (cellBean == null) {
                continue;
            }
            if (cellBean.getContentType().equals(CellBean.CellContentType.TEXT)) {
                // 普通文本
                String value = cellBean.getValue().toString();
                int width = getCellColumnWidth(value);
                int currentWidth = sheet.getColumnWidth(i);
                if (currentWidth < width) {
                    sheet.setColumnWidth(i, width);
                }
                cell.setCellValue(value);
            } else if (cellBean.getContentType().equals(CellBean.CellContentType.FX)) {
                // 公式

                // 获取列坐标前缀
                CellAddress cellAddress = cell.getAddress();
                String address = cellAddress.formatAsString();
                address = address.replaceAll(String.valueOf(cellAddress.getRow() + 1), "");

                // 计算起始行号、结束行号(行号=行索引+1)
                int startRowNum = titleColNum + 1;
                // 结束行在当前行上一行
                int endRowNum = rowIndex;

                // 拼接公式
                StringBuilder sb = new StringBuilder();
                sb.append(cellBean.getValue().toString()).append("(");
                sb.append(address).append(startRowNum).append(":");
                sb.append(address).append(endRowNum).append(")");

                cell.setCellFormula(sb.toString());
            }
        }
        return wb;
    }






    /**
     * 获取对象属性的get方法集合
     * @param cls 对象类型
     * @param fieldList 属性集合
     * @return get方法集合
     */
    private static Map<String, Method> getGetMethodMap(Class cls, List<Field> fieldList) {
        Map<String, Method> methodMap = new HashMap<>();
        for (Field field : fieldList) {
            field.setAccessible(true);
            try {
                PropertyDescriptor pd = new PropertyDescriptor(field.getName(), cls);
                Method readMethod = pd.getReadMethod();
                methodMap.put(field.getName(), readMethod);
            } catch (Exception e) {

            }
        }
        return methodMap;
    }





    /**
     * 根据单元格内容值，计算单元格宽度<br>
     * 注：最小宽度为5个字符、最大宽度为100个字符
     * @param value 根据单元格内容值
     * @return 计算后的宽度
     */
    private static int getCellColumnWidth(String value) {
        final int v = 256;
        // 单元格宽度最小5个字符
        final int minLength = 5;
        // 单元格宽度最大100个字符
        final int maxLength = 100;

        if (StringUtils.isBlank(value)) {
            return minLength * v;
        }
        int length = value.getBytes().length + 1;
        if (length > maxLength) {
            length = maxLength;
        }
        int width = length * v;

        return width;
    }


    /**
     * 多层级map对象取值<br>
     * 注：只支持map集合嵌套map集合的取值
     * @param key 多层级key(例：user.name)
     * @param dataMap map集合对象
     * @return 取值结果
     */
    private static Object getValueForMap(String key, Map<String, Object> dataMap) {
        if (StringUtils.isBlank(key)) {
            return null;
        }
        if (!key.contains(".") || key.startsWith(".") || key.endsWith(".")) {
            return dataMap.get(key);
        }
        String[] keys = key.split("\\.");
        if (StringUtils.isBlank(keys[0])) {
            return null;
        }
        Object obj = dataMap.get(keys[0]);
        if (!(obj instanceof Map)) {
            return obj;
        }
        Map map = (Map) obj;
        for (int i = 1; i < keys.length; i++) {
            String k = keys[i];
            if (StringUtils.isBlank(k)) {
                return null;
            }
            Object o = map.get(k);
            if (!(o instanceof Map)) {
                return o;
            } else {
                map = (Map) o;
            }
        }
        return null;
    }

}
